import UIKit

var str = "Hello, playground"
//如果Player中的name需要能被重写，那么关键字就不能用static，只能用class
class Player {
    class var name : String {
        return "玩家"
    }
    class func serverName() {
        print("\(Player.name)在上海电信一区")
    }
}

class BeijingPlayer: Player {
    override class var name :String {
        return "土豪玩家"
    }
    
    override class func serverName() {
        print("\(BeijingPlayer.name)在北京联通2区")
    }
}

Player.serverName()
BeijingPlayer.serverName()


//枚举只能用static

struct Reborn {
    static var hp = 100
    static func place(){
        print("您在安全区复活")
    }
}
Reborn.place()
Reborn.hp



//下标是访问集合，列表数列中元素的快捷方式

//subscript(index :参数类型) ->返回类型 {
//    get {}
//    set {}
//}

var topProvinces = ["GD","JS","SD","ZJ"]
topProvinces[1]
var gdpRank = ["JS":70116,"SD":63002,"GD":72831,"ZJ":42886]

struct Cycle {
    func Arear(r:Double) -> Double {
        return Double.pi * pow(r, 2)
    }
    subscript(r:Double) -> Double {
        return Double.pi * pow(r, 2)
    }
}

let cycle1 = Cycle()
cycle1.Arear(r: 5)

cycle1[5]

//继承：class之间的父子关系的提现
//子类可以继承父类的属性和方法

class Che {
    var speed = 0
    var desc: String
    {
        return "时速是\(speed)km/h"
    }
    func makeNoise() {
        
    }
}

class Bike : Che {
    var hasbasket = false
}

let aBike = Bike()
aBike.speed = 40
aBike.desc
aBike.hasbasket = true
aBike.makeNoise()


class CRH : Che {
    override func makeNoise() {
        print("滴滴滴")
    }
}

let aCRH = CRH()
aCRH.makeNoise()


//如果这个类不想其他类来继承,class前面加final关键字

final class loverBike : Bike {
    var rides = 2
}

//报错，不能被继承
//class triBike : loverBike {
//
//}


//错误处理，try-catsh,反映运算的出错细节，恢复程序的过程

//一个函数可以加上throws关键字，表示可以处理错误。这个函数的调用者可以捕获（catch）这个错误并进行应对

func method1() throws {
    print("我是一个函数")
}

try method1()

//处理更细分的错误情况，错误类型需要遵循Error协议

enum LearningObsetacle :Error {
    case noMethod,noReading,noTool(WithMac:String)
}

func iosLearning(hasMethod:Bool, hasWay:Bool,hasTool:Bool) throws {
    guard hasMethod else {
        throw LearningObsetacle.noMethod
    }
    
    guard hasWay else {
        throw LearningObsetacle.noReading
    }
    
    guard hasTool else {
        throw LearningObsetacle.noTool(WithMac: "没有Mac电脑")
    }
}

var budget = 7000

func purchase(tool:String) {
    if budget >= 6000 {
        budget -= 6000;
        print("您已采购",tool,"花费了6000，余额是",budget)
    }else {
        print("资金不足")
    }
}

do {
    try iosLearning(hasMethod: true, hasWay: true, hasTool: true)
    print("成功开始学习")
} catch LearningObsetacle.noMethod {
    print("打开学习网站")
} catch LearningObsetacle.noReading {
    print("看网站视频")
}catch LearningObsetacle.noTool(let mac) {
    purchase(tool: mac)
}


if let result = try? iosLearning(hasMethod: true, hasWay: true, hasTool: true){
    print("愉快的学习")
}else {
    print("学习失败")
}


//try! iosLearning(hasMethod: false, hasWay: true, hasTool: true) //条件不满足程序就崩溃调了


//特定的收尾工作。defer语句

func pk() {
//    推迟执行
    defer {
        print("Game Over")
    }
    print("Fight!")
    print("You VS xiaobo")
}


//闭包，Closure
//闭包是一种函数的简写形式，省去函数名，把参数和返回值放入花括号内。
//{ (a: Int, b:Int) -> Int in
//    执行语句
//    return ....
//}
//场景，一个函数的额一个参数是另一个函数 时候，另一个函数可以用闭包来表示

//sort函数

var citys = ["zhengzhou","xiamen","hefei","nanchang"]
func daoxu(a : String, b : String) -> Bool {
    return a > b
}
func shunxu(a : String, b : String) -> Bool {
    return a < b
}

let cityRank1 = citys.sorted(by: daoxu)

let cityRank2 = citys.sorted(by: shunxu)


//闭包表达式来改写

let cityRank3 = citys.sorted { (a, b) -> Bool in
    return a < b
}

//闭包自动推断
//1.参数类型可自动推断，单表达式可以忽略return关键字
//2.可使用快捷参数，前$，从0开始递增
let cityRank4 = citys.sorted {
    $0 > $1
}
//进一步简化
let cityRank6 = citys.sorted(by: >)




//枚举
//枚举enumeration
//计数、列举（有限情况）通常与switch语句结合使用

enum Weather {
    case sunny,cloudy,rainy,snow,froggy,snown
}

Weather.cloudy

//与switch语句配合使用

var todayWeather = Weather.rainy

switch todayWeather {
case .cloudy:
    print("多云")
case .sunny:
    print("晴天")
default:
    print("天气状况未知")
}

//附加值，每一种类型都可以附加一个或者多个值，形式是元组。case 类型 （Int,String...）

enum AccurateWeather {
    case rainy(Double, Int, String)
    case froggy(String, Int)
}

let shanghaiTodayWeather = AccurateWeather.rainy(0.8, 100, "小雨")
let beijingTodayWeather = AccurateWeather.froggy("PM2.5", 300)

switch shanghaiTodayWeather {
case .rainy(let gailv, let volume, let desc):
    print("降雨概率：",gailv,"雨量",volume,"雨的类型",desc)
default:
    break;
}


